package main;

import java.awt.Point;
import java.io.File;
import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Scanner;

import nmf.NMFTool;
import nmf.NMFTool.Results;
import nmf.TitleFeatureNMFTool;

import org.ejml.simple.SimpleMatrix;

import svm.matrixToFile;
import svm.run_svm;
import utils.ClassificationUtil;

public class NMFTestProcessFixedR extends Thread {
   
   public ArrayList<String> fileNames;
   public ArrayList<NMFTool> nmfTools;
   int rValue, trainingSetSize;
   //X is number classified correctly
   //Y is total number
   HashMap<NMFTool, Point> map = new HashMap<NMFTool, Point>();
   public static ArrayList<Integer> rValues;
   public static String breakRegEx = "[.[^a-zA-Z]]";
   
   public synchronized HashMap<NMFTool, Point> getMap() {
      return map;
   }
   
   public NMFTestProcessFixedR(final ArrayList<String> fileNames,
         final ArrayList<NMFTool> nmfTools, final ArrayList<Integer> rValues, final int trainingSetSize) {
      this.fileNames = fileNames;
      this.nmfTools = nmfTools;
      NMFTestProcessFixedR.rValues = rValues;
      this.trainingSetSize = trainingSetSize;
   }
   
   /**
    * Fills out a HashMap with the Shit we need.
    */
   @Override
   public synchronized void run() {
      try {
         final SummaryInfo[][][] summaries = new SummaryInfo[rValues.size()][nmfTools.size()][fileNames.size()];
         
         for (int currentDocCol = 0; currentDocCol < fileNames.size(); currentDocCol++) {
            final int[] actualClass = ReutersTest.
                  classifications(fileNames.get(currentDocCol));
            
            final String[] fileNamesWorkAround = new String[1];
            fileNamesWorkAround[0] = fileNames.get(currentDocCol);
            //MAY NEED TO DO SOMETHING HERE
            final SimpleMatrix V = ClassificationUtil.getPreProcessedMatrix(fileNamesWorkAround, false);
            
            final int[] trainClass = new int[trainingSetSize];
            
            for (int i = 0; i < trainClass.length; i++) {
               trainClass[i] = actualClass[i];
            }

            //loop over number of times we want simple to be repeated.
            for (int innerDimIndx = 0; innerDimIndx < rValues.size(); innerDimIndx++) {
               for (int toolNum = 0; toolNum < nmfTools.size(); toolNum++) {
                  if (map.get(nmfTools.get(toolNum)) == null) {
                     map.put(nmfTools.get(toolNum), new Point(0, 0));
                  }
                  
                  if (rValues.get(innerDimIndx) == -1) {
                     rValue = (int) Math.ceil((double) (V.numCols() * V.numRows()) / (V.numCols() + V.numRows()));
                  }
                  else {
                     rValue = rValues.get(innerDimIndx);
                  }
                  
                  final Results res = nmfTools.get(toolNum).factor(V, rValue, trainClass);
                  final SimpleMatrix m_train_nmf = res.H.extractMatrix(0, res.H.numRows(), 0, trainClass.length);
                  
                  ReutersTest.write_file("src/svm/matrix_file_nmf", res.H.transpose());
                  ReutersTest.write_file("src/svm/matrix_file_train_nmf", m_train_nmf.transpose());
                  
                  final matrixToFile mft = new matrixToFile("src/svm/matrix_file_train_nmf", true, trainClass);
                  final matrixToFile mfc = new matrixToFile("src/svm/matrix_file_nmf", false, actualClass);
                  final run_svm svm = new run_svm("svmTrain", "svmFile", "svmOut");
                  
                  final FileInputStream in = new FileInputStream(new File("svmOut"));
                  final Scanner sc = new Scanner(in);
                  double currentClass;
                  //System.out.println("Classifications from SVM with factoring: \n");
                  
                  for (int i = 0; sc.hasNext(); i++) {
                     currentClass = sc.nextDouble();
                     map.get(nmfTools.get(toolNum)).y++;
                     if (i == actualClass.length) {
                        System.out.println("Uh oh.");
                     }
                     if (currentClass == actualClass[i]) {
                        map.get(nmfTools.get(toolNum)).x++;
                        //System.out.print(currentClass + " ");
                     }
                  }
                  //System.out.println("\n");
                  mfc.deleteFiles();
                  mft.deleteFiles();
                  svm.deleteFiles();
                  
               }
               for (int toolNumIter = 0; toolNumIter < nmfTools.size(); toolNumIter++) {
                  summaries[innerDimIndx][toolNumIter][currentDocCol] = new SummaryInfo(nmfTools.get(toolNumIter).toString(), rValue, map.get(nmfTools.get(toolNumIter)).x, map.get(nmfTools.get(toolNumIter)).y);
               }
               
               map.clear();
            }
            
         }
         double totalCorrect = 0, totalDocs = 0;
         for (int innerDim = 0; innerDim < rValues.size(); innerDim++) {
            for (int toolNum = 0; toolNum < nmfTools.size(); toolNum++) {
               final SummaryInfo acrossDocumentSummary = new SummaryInfo();
               acrossDocumentSummary.rValue = summaries[innerDim][toolNum][0].rValue;
               acrossDocumentSummary.nmfTool = nmfTools.get(toolNum).toString();
               for (int currentDocCol = 0; currentDocCol < fileNames.size(); currentDocCol++) {
                  acrossDocumentSummary.numberOfDocumentsClassifiedCorrectly += summaries[innerDim][toolNum][currentDocCol].numberOfDocumentsClassifiedCorrectly;
                  acrossDocumentSummary.totalNumberOfDocuments += summaries[innerDim][toolNum][currentDocCol].totalNumberOfDocuments;
               }
               totalCorrect += acrossDocumentSummary.numberOfDocumentsClassifiedCorrectly;
               totalDocs += acrossDocumentSummary.totalNumberOfDocuments;
               acrossDocumentSummary.printSummaryInfo();
            }
         }
         if (nmfTools.size() == 1) {
            System.out.println("Average Accuracy: " + totalCorrect / totalDocs);
         }
         System.out.println("Training Set Size: " + trainingSetSize);
         ClassificationUtil.writeToCSV(summaries, "outPut//currentRun.csv");
      }
      catch (final Exception e) {
         System.out.println("NMF Process Failed.\n");
         e.printStackTrace();
      }
   }
   
   public static class SummaryInfo {
      public String nmfTool;
      public int rValue;
      public int numberOfDocumentsClassifiedCorrectly;
      public int totalNumberOfDocuments;
      
      public SummaryInfo(final String nmfTool, final int rValue, final int NoDCC, final int tNoD) {
         this.nmfTool = nmfTool;
         this.rValue = rValue;
         numberOfDocumentsClassifiedCorrectly = NoDCC;
         totalNumberOfDocuments = tNoD;
      }
      
      public SummaryInfo() {
         
      }
      
      public void printSummaryInfo() {
         System.out.println("\n" + nmfTool + ", rValue = " + rValue + ":");
         System.out.println("Total number classified correctly: " + numberOfDocumentsClassifiedCorrectly);
         System.out.println("Total number of documents: " + totalNumberOfDocuments + "\n");
      }
   }
   
}
